#include "minicap.h"
#include <QtCore>
#include "adbutils.h"
#include <QtCore/qdir.h>
#include "settings.h"

MiniCap::MiniCap(QObject *parent) : QObject(parent),
    serverProcess(nullptr)
{
}

MiniCap::~MiniCap()
{
    if (nullptr != serverProcess) {
        serverProcess->close();
        delete serverProcess;
    }
}

QMutex MiniCap::mutex;
QAtomicPointer<MiniCap> MiniCap::instance = 0;

MiniCap* MiniCap::getInstance()
{
#ifndef Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE
    if(!QAtomicPointer<MiniCap>::isTestAndSetNative())
        qDebug("Error: TestAndSetNative not supported!");
#endif

    if(instance.testAndSetOrdered(0, 0))
    {
        QMutexLocker locker(&mutex);
        instance.testAndSetOrdered(0, new MiniCap);
    }
    return instance;
}

int MiniCap::prepare() {
    int device = AdbUtils::getDevicesNum();
    if (device > 1) return -1;
    if (device <= 0) return -2;
    QString abi = AdbUtils::getProp(ABI_PROP);
    if (abi.length() <= 0) return -3;
    QString sdk = AdbUtils::getProp(SDK_PROP);
    if (sdk.length() <= 0) return -4;
    QString pre_sdk = AdbUtils::getProp(PRE_PROP);
    if (pre_sdk.length() <= 0) return -5;
    QString rel_ver = AdbUtils::getProp(REL_PROP);
    if (rel_ver.length() <= 0) return -6;
    if (sdk.toInt() >= 16) {
        binName = MINI_CAP_BINARY_NAME;
    } else {
        binName = MINI_CAP_BINARY_NAME_NO_PIE;
    }

    AdbUtils::mkdir( MINI_EXECUTE_DEVICE_DIR);
    AdbUtils::push(MINI_CAP_BINARY_DIR.append(abi).append("/").append(binName), MINI_EXECUTE_DEVICE_DIR);
    QFile libFile(MINI_CAP_LIB_DIR.append("android-").append(rel_ver).append("/").append(abi).append("/").append(MINI_CAP_LIB_NAME));
    if (libFile.exists()) {
        AdbUtils::push(MINI_CAP_LIB_DIR.append("android-").append(rel_ver).append("/").append(abi).append("/").append(MINI_CAP_LIB_NAME), MINI_EXECUTE_DEVICE_DIR);
    } else {
        AdbUtils::push(MINI_CAP_LIB_DIR.append("android-").append(sdk).append("/").append(abi).append("/").append(MINI_CAP_LIB_NAME), MINI_EXECUTE_DEVICE_DIR);
    }
    AdbUtils::chmod("777", MINI_EXECUTE_DEVICE_DIR.append(binName));
    return 0;
}

int MiniCap::startServer() {
    Settings *settings = Settings::getInstance();
    int width = settings->getDisWidth();
    int height = AdbUtils::getDisHeight(width);
    QString deviceSize = AdbUtils::getDeviceSize();
    qDebug() << "mini_cap Server dis start width" << width << "hegith" << height;
    QString cmd = QString(MINI_CAP_EXECUTE_BASE_CMD)
            .append(binName).append(" -P ")
            .append(deviceSize).append("@")
            .append(QString::number(width)).append("x").append(QString::number(height)).append("/0");

    if (nullptr == serverProcess) {
        serverProcess = new QProcess();
    }

    QStringList cmd_list = cmd.split(" ");
    cmd_list.insert(0, "shell");
    QString program = settings->getAdbPath();
    if (program.length() <= 0) {
        return -1;
    }
    QStringList arguments;
    for (int i = 0; i < cmd_list.size(); ++i) {
        arguments.append(cmd_list[i]);
    }
    qDebug() << "startServer" << program << "; params" << arguments;
    serverProcess->start(program, arguments);
    //process.waitForFinished();
    //QByteArray error = process.readAllStandardError();
    //QByteArray out = process.readAllStandardOutput();
   // qDebug() << "error" << error << "out" << out;
    //return QString(out);

    qDebug() << "mini_cap Server stop";
    return 0;
}

const int DataSize = 100000;

const int BufferSize = 8192;
char buffer[BufferSize];
int numUsedBytes = 0;


QWaitCondition bufferNotEmpty;
QWaitCondition bufferNotFull;
QMutex mutex;

class Producer : public QThread
{
public:
    Producer(QObject *parent = NULL) : QThread(parent)
    {
    }

    void run() override
    {
        qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));

        for (int i = 0; i < DataSize; ++i) {
            mutex.lock();
            if (numUsedBytes == BufferSize)
                bufferNotFull.wait(&mutex);
            mutex.unlock();

            buffer[i % BufferSize] = "ACGT"[(int)qrand() % 4];

            mutex.lock();
            ++numUsedBytes;
            bufferNotEmpty.wakeAll();
            mutex.unlock();
        }
    }
};

class Consumer : public QThread
{
    Q_OBJECT
public:
    Consumer(QObject *parent = NULL) : QThread(parent)
    {
    }

    void run() override
    {
        for (int i = 0; i < DataSize; ++i) {
            mutex.lock();
            if (numUsedBytes == 0)
                bufferNotEmpty.wait(&mutex);
            mutex.unlock();

            fprintf(stderr, "%c", buffer[i % BufferSize]);

            mutex.lock();
            --numUsedBytes;
            bufferNotFull.wakeAll();
            mutex.unlock();
        }
        fprintf(stderr, "\n");
    }

signals:
    void stringConsumed(const QString &text);
};
